package cn.zhqr.core.controller.base;

import cn.zhqr.common.bean.UserInfo;
import cn.zhqr.common.bean.response.ErrorCode;
import cn.zhqr.common.bean.response.OutResponse;
import cn.zhqr.common.config.GlobalConstants;
import cn.zhqr.common.exception.ErrorCodeException;
import cn.zhqr.common.exception.SessionTimeoutException;
import cn.zhqr.common.util.collections.Lists;
import cn.zhqr.common.util.str.UUIDUtil;
import cn.zhqr.common.utils.DateUtils;
import cn.zhqr.core.component.UserInfoHolder;
import cn.zhqr.core.component.UserInfoKit;
import cn.zhqr.core.component.UserInfoManager;
import cn.zhqr.core.interceptor.LoginInterceptor;
import cn.zhqr.core.interceptor.UncaughtExceptionInterceptor;
import cn.zhqr.core.utils.BrandKit;
import com.alibaba.fastjson.JSON;
import com.jfinal.core.ActionException;
import com.jfinal.core.Controller;
import com.jfinal.core.Injector;
import com.jfinal.core.NotAction;
import com.jfinal.ext.plugin.tx.DbTxExceptionHandler;
import com.jfinal.kit.HttpKit;
import com.jfinal.kit.StrKit;
import com.jfinal.log.Log;

import javax.servlet.http.HttpServletRequest;
import java.lang.reflect.Method;
import java.math.BigDecimal;
import java.math.BigInteger;
import java.text.ParseException;
import java.util.Date;
import java.util.HashSet;
import java.util.List;
import java.util.Set;

/**
 * controller的基类，封装controller常用方法
 * Created by charles on 2017/4/4.
 */
public abstract class BaseController extends Controller implements UserInfoHolder, DbTxExceptionHandler {
    private static String userInfoAttrName = "user_info";
    private static String userTokenAttrName = "user_auth_token";

    public static Log log = Log.getLog(BaseController.class);
    public <T> T getBean(Class<T> beanClass) {
        return Injector.injectBean(beanClass,"",this.getRequest(), true);
    }

    @Override
    public void setUserInfo(String token, UserInfo userInfo){
        setAttr(userInfoAttrName,userInfo);
        setAttr(userTokenAttrName,token);
    }

    /**
     * 获取用户ID,如果未登录则抛出SessionTimeoutException
     * @return
     */
    public UserInfo getUserInfo(){
        UserInfo userInfo = getAttr(userInfoAttrName);
        if(userInfo==null){
            throw new SessionTimeoutException();
        }
        return userInfo;
    }

    /**
     * 更新UserInfo缓存
     * @param userInfo
     */
    public void updateUserInfo(UserInfo userInfo){
        String token = getToken();
        UserInfoManager userInfoManager = UserInfoKit.getManager(LoginInterceptor.class);
        if(userInfoManager != null){
            userInfoManager.setUserInfo(token,userInfo);
        }
        setAttr(userInfoAttrName,userInfo);
    }

    /**
     * 获取UserInfo，如果未登录则会返回null
     * @return
     */
    public UserInfo getUserInfoIfLogin(){
        UserInfo userInfo = getAttr(userInfoAttrName);
        return userInfo;
    }

    /**
     * 获取用户id,如果未登录则抛出SessionTimeoutException
     * @return
     */
    public Long getUserId(){
        UserInfo userInfo = getUserInfo();
        return  userInfo.getUserid();
    }

    /**
     * 获取用户id，如果未登录则返回空
     * @return
     */
    public Long getUserIdIfLogin(){
        UserInfo userInfo = getUserInfoIfLogin();
        if(userInfo==null){
            return null;
        }
        return  userInfo.getUserid();
    }

    public Long getAgentId(){
        UserInfo userInfo = getUserInfo();
        return  userInfo.getAgent_id();
    }

    public Long getAgentIdIfLogin(){
        UserInfo userInfo = getUserInfoIfLogin();
        if(userInfo==null){
            return null;
        }
        return  userInfo.getAgent_id();
    }

    /**
     * 获取当前登录鉴权token
     * @return
     */
    public String getToken(){
        return getAttr(userTokenAttrName);
    }

    /**
     * 获取品牌编码
     * @return
     */
    public String getBrandCode(){
        String brandCode = getRequest().getHeader(GlobalConstants.BRAND_HTTP_HEADER);

        if(!BrandKit.isExists(brandCode)) return BrandKit.DEFAULT_BRAND;

        BrandKit.setThreadLocalBrandCode(brandCode);
        return brandCode;
    }

    /**
     * 清除token
     */
    public void clearToken(){
        String token = getToken();
        UserInfoManager userInfoManager = UserInfoKit.getManager(LoginInterceptor.class);
        if(userInfoManager != null){
            userInfoManager.removeUserInfo(token);
        }

        removeAttr(userInfoAttrName);
        removeAttr(userTokenAttrName);
    }

    /**
     * 创建token
     * @param userInfo
     */
    public void createToken(UserInfo userInfo){
        String token = UUIDUtil.randomUUID();

        UserInfoManager userInfoManager = UserInfoKit.getManager(LoginInterceptor.class);
        if(userInfoManager != null){
            userInfoManager.setUserInfo(token,userInfo);
        }

        userInfo.setToken(token);
    }


    public BigDecimal getParaToBigDecimal(String name){
        return getParaToBigDecimal(name,null);
    }

    public BigDecimal getParaToBigDecimal(String name,BigDecimal defaultValue){
        String value = getPara(name);
        if(StrKit.isBlank(value)){
            return defaultValue;
        }
        try{
            return new BigDecimal(value);
        }catch (Exception e){
            log.error("Invalid param ："+name);
            return defaultValue;
        }
    }

    public BigInteger getParaToBigInteger(String name){
        return getParaToBigInteger(name,null);
    }

    public BigInteger getParaToBigInteger(String name, BigInteger defaultValue){
        String value = getPara(name);
        if(StrKit.isBlank(value)){
            return defaultValue;
        }
        try{
            return new BigInteger(value);
        }catch (Exception e){
            log.error("Invalid param ："+name);
            return defaultValue;
        }
    }

    public Set<Integer> getParaValuesToIntSet(String name) {
        String[] values = getRequest().getParameterValues(name);
        if (values == null)
            return null;
        Set<Integer> result = new HashSet<>();

        for (int i=0; i<values.length; i++){
            if(values[i]!=null && values[i].trim().length()>0){
                Integer int_value = Integer.parseInt(values[i]);
                if(!result.contains(int_value)){
                    result.add(int_value);
                }
            }
        }

        return result;
    }

    public String getPara(String name) {
        String str = super.getPara(name);
        return str==null?null:str.trim();
    }

    public String getPara(String name,String default_value) {
        String str = super.getPara(name);
        return str==null?default_value:str.trim();
    }

    private static final List<String> date_formats = Lists.arrayList("yyyy-MM-dd HH:mm:ss","yyyy-MM-dd HH:mm","yyyy-MM-dd","yyyy-MM");

    public Date getParaToDate(String name) {
        String value = getPara(name);
        if(StrKit.isBlank(value)){
            return null;
        }
        Date date = null;
        for(String format : date_formats){
            date = DateUtils.parseDate(value,format);
            if(date!=null){
                return date;
            }
        }
        log.warn("parseDate error :"+value);
        return null;
    }

    public Date getParaToDateEnd(String name) {
        String value = getPara(name);
        if(StrKit.isBlank(value)){
            return null;
        }
        Date date = null;
        for(String format : date_formats){
            date = DateUtils.parseDate(value,format);
            if(date!=null){
                return new Date(date.getTime()+24*3600*1000-1);
            }
        }
        return null;
    }

    public Date getParaToDate(String name,String format){
        String value = getPara(name);
        if(StrKit.isBlank(value)){
            return null;
        }
        try {
            return DateUtils.getDateFormat(format).parse(value);
        } catch (ParseException e) {
            return null;
        }
    }

    public Long getParaToDateSecond(String name){
        Date date = getParaToDate(name);
        return date==null?null:date.getTime()/1000;
    }
    public Long getParaToDateSecond(String name,Long default_value){
        Date date = getParaToDate(name);
        return date==null?default_value:date.getTime()/1000;
    }

    public Long getParaToDateEndSecond(String name){
        Date date = getParaToDate(name);
        return date==null?null:date.getTime()/1000+24*3600-1;
    }
    public Long getParaToDateEndSecond(String name,Long default_value){
        Date date = getParaToDate(name);
        return date==null?default_value:date.getTime()/1000+24*3600-1;
    }

    public <T> T getParaToObject(String name,Class<T> clazz) {
        String para = getPara(name);
        if(StrKit.notBlank(para)){
            try{
                return JSON.parseObject(para,clazz);
            }catch (Exception e){
                log.error("Invalid param ：paygivce");
            }
        }
        return null;
    }


    /**
     * 输出成功的json
     * @param data
     */
    public void renderSuccessJson(String msg,Object data){
        renderJson(OutResponse.buildSuccess(msg,data));
    }

    public void renderSuccessJson(Object data){
        renderJson(OutResponse.buildSuccess(data));
    }

    public void renderSuccessJson(){
        renderJson(OutResponse.buildSuccess());
    }

    /**
     * 输出错误的json
     * @param errorCode
     */
    public void renderErrorJson(ErrorCode errorCode){
        renderJson(OutResponse.buildError(errorCode));
    }

    /**
     * 输出错误的json
     * @param errorCode
     * @param msg
     */
    public void renderErrorJson(ErrorCode errorCode,String msg){
        renderJson(OutResponse.buildError(errorCode.code,msg));
    }
    public void renderErrorJson(Integer code,String msg){
        renderJson(OutResponse.buildError(code,msg));
    }
    public void renderErrorJson(Integer code,String msg,Object data){
        renderJson(OutResponse.buildError(code,msg,data));
    }

    public void renderJsonp(String callback,Object data){
        renderText(callback+"("+JSON.toJSONString(data)+")");
    }

    public void returnErrorJson(ErrorCode errorCode,String msg){
        throw new ErrorCodeException(errorCode.code,msg);
    }
    public void returnErrorJson(Integer code,String msg){
        throw new ErrorCodeException(code,msg);
    }
    public void returnErrorJson(Integer code,String msg,Object data){
        throw new ErrorCodeException(code,msg,data);
    }

    public void returnErrorJson(ErrorCode errorCode){
        throw new ErrorCodeException(errorCode.code,errorCode.msg);
    }
    /**
     * 获取请求参数并转换为double类型，如果没有，或格式转换失败，则返回默认值
     * @param name
     * @param defaultValue 默认值
     * @return
     */
    public Double getParaToDouble(String name, Double defaultValue){
        return toDouble(getPara(name),defaultValue);
    }
    public Double getParaToDouble(String name){
        return getParaToDouble(name, null);
    }
    private Double toDouble(String value, Double defaultValue){
        try {
            if (value == null || "".equals(value.trim()))
                return defaultValue;
            value = value.trim();
            if (value.startsWith("N") || value.startsWith("n"))
                return -Double.parseDouble(value.substring(1));
            return Double.parseDouble(value);
        }
        catch (Exception e) {
            throw new ActionException(404, getRender(),  "Can not parse the parameter \"" + value + "\" to Long value.");
        }
    }

    public String getRequestBody(){
        return HttpKit.readData(getRequest());
    }
    public <T> T getRequestJSON(Class<T> clazz){
        return JSON.parseObject(getRequestBody(),clazz);
    }

    @Override
    @NotAction
    public void onExceptionError(Object o, Method method, Exception e) {
        OutResponse response = UncaughtExceptionInterceptor.handleException(e);
        renderJson(response);
    }

    public String getRemoteHost(){
        HttpServletRequest request = getRequest();
        String ip = request.getHeader("x-forwarded-for");
        if(ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)){
            ip = request.getHeader("Proxy-Client-IP");
        }
        if(ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)){
            ip = request.getHeader("WL-Proxy-Client-IP");
        }
        if(ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)){
            ip = request.getRemoteAddr();
        }
        return ip.equals("0:0:0:0:0:0:0:1")?"127.0.0.1":ip;
    }

    public static void setUserInfoAttrName(String name){
        userInfoAttrName = name;
    }

    public static String getUserInfoAttrName(){
        return userInfoAttrName;
    }
}
